最近遇见一个问题, 我在维护一个a.com域名下的UISDK,这个UISDK是要开放出去给其他开发者使用的,开发者可以通过iframe来使用. 那么就存在一个跨域的问题,在chrome下还好.问题出在safari中,发现所有的cookie都设置不上.
触发原因
找寻资料后发现,safari和其他一些现代浏览器,有一个安全策略,就是非用户主动打开的web, 禁止其设置cookie.而通过iframe打开的界面,就被判定为非用户主动打开的界面,所以a.com这个网站任何cookie都设置不了.
解决方案
网上目前有以下几种解决方案:
- 出镜次数最多的方案, 设置P3P Header, 这个方案应该是最简单的了,需要打开iframe的网站添加一个P3P的请求头,但是这个方法safari浏览器不支持,IE系列还好,而且让开发者在自己的网站中做这种修改,是比较不友好的,而且可能会有安全问题
- 模拟post表单提交,这是个比较不常规的方法,在safari高版本中已经修复了,而且听说谷歌因为一直绕过safari的安全策略读取第三方cookie,被苹果起诉了,所以这种方法也已经凉了.
- 根据safari的安全策略,如果用户曾经访问过a.com,那么即使通过iframe的方式使用也可以设置cookie.所以可以在iframe中进行判断,如果设置不了cookie,通过window.parent.location.href = ‘a.com’; 的方式使浏览器主动访问一次 a.com,然后a.com再跳回原界面,这样之后也会正常设置cookie
- 此方案应该是和3是一样的,如果浏览器中存在a.com的cookie,那么再通过iframe访问也可以设置cookie.这个可以通过3的方法去解决.但是3,4这两种方法用户感知太强烈,不是很友好
网上找的几种方案都不合适,只能自己想办法了.
寻求新方案
cookie存不了,但是localStorage是可以的啊,那就可以把数据存在localStorage中
开始解决:
首先要把数据传到前端,之前是通过set-cookie的方式,那这里肯定用不了,那就通过query吧
在前端通过query拿到数据,成功存到localStorage, 完成第一步
又发现一个问题,没有cookie的话,后续请求接口也没有cookie,用户信息带不上,后端没法处理
那既然数据都存在localStorage中,把他拿出来放到请求头 的 cookie 中不就可以了吗
尝试后发现, 这个方法浏览器不允许, 这是一种不安全的方法, 所以这条路行不通
又陷入了一个死局,后端通过cookie去拿用户信息,这里cookie带不上,怎么解决,只能改变后端拿数据的方式, 总不能又把数据放到query中传过去,那岂不是每个接口都要改,而且query中带了太多东西
最后的最后,在http请求中发现了有用的东西,那就是ctx.request.headers['referer']
, 因为最开始为了将数据传到前端将其放在了url的query中,那么以后从这个界面发起的请求中就已经全部带着这些数据, 当从cookie中拿不到数据的时候,从referer
中取一下就好了,至此这个问题以一种很奇葩的方式解决了
反思
问题虽然解决了,但是我觉得这种方案并不能通用,通过query + cookie(referer)
来取数据还有一些约束,比如referer很可能在客户端被改变等等
那么最好的方案是什么呢,在我看来,使用jwt
来做这个事情是非常合适的,将很少的信息加密后通过query或者其他方式放到前端,前端可以使用任何方式存储,最主要的是可以通过设置Authorization
将数据很方便的带到后端, 可以带来更好的安全性和稳定性